Monadic Fold, Monadic Build, Monadic Short Cut Fusion
نویسنده
چکیده
Short cut fusion improves the efficiency of modularly constructed programs by eliminating intermediate data structures produced by one program component and immediately consumed by another. We define a combinator which expresses uniform production of data structures in monadic contexts, and is the natural counterpart to the well-known monadic fold which consumes them. Like the monadic fold, our new combinator quantifies over monadic algebras rather than standard ones. Together with the monadic fold, it gives rise to a new short cut fusion rule for eliminating intermediate data structures in monadic contexts. This new rule differs significantly from previous short cut fusion rules, all of which are based on combinators which quantify over standard, rather than monadic, algebras. We give examples illustrating the benefits of quantifying over monadic algebras, prove our new fusion rule correct, and show how it can improve programs. We also consider its coalgebraic dual. 1 THE PROBLEM Consider the following variation on the well-known problem of fusing modular list-processing functions [5]. Suppose we want to sum the cubes of all the integers in a list. Suppose further that cubing any of the integers in the list can generate an out-of-range error, and that each of the partial sums of their cubes can also generate an out-of-range error. If out-of-range errors are tested for using outOfRange :: Int -> Maybe Int, where the datatype data Maybe a = Nothing | Just a is the standard error-handling monad given in the Haskell prelude, then it is natural to write this program as the composition of two functions: i) a function mmapcube :: [Int] -> Maybe [Int] which checks whether the cube of any integer in its input list generates an out-of-range error and, if so, propagates the error, and ii) a function msum :: [Int] -> Maybe Int which sums the elements of a list of integers, checking along the way whether each accumulated partial sum generates an out-of-range error. We’d have msumOfCubes xs = mmapcube xs >>= msum where Nothing >>= k = Nothing and Just x >>= k = k x, as usual. If we want to optimize this program by eliminating the intermediate structure of type Maybe [Int] produced by mmapcube and consumed by \x -> x >>= msum, then we might look to the standard short cut — i.e., fold/build — fusion rule [5] for inspiration. Recalling that >>= is the analogue of composition for monadic computations, we first observe that the pure analogues mapcube and sum of the monadic functions mmapcube and msum above can be written in terms of the wellknown uniform list-consuming and -producing functions foldr and build given in Figure 1. Letting cube x = x * x * x we have mapcube :: [Int] -> [Int] mapcube xs = build (\c n -> foldr (c . cube) n xs) University of Strathclyde, Glasgow, Scotland, {patricia,ng}@cis.strath.ac.uk. foldr :: (b -> a -> a) -> a -> [b] -> a foldr c n [] = n foldr c n (x:xs) = c x (foldr c n xs) build :: (forall a. (b -> a -> a) -> a -> a) -> [b] build g = g (:) [] foldr c n (build g) = g c n FIGURE 1. The foldr and build combinators and foldr/build rule for lists. sum :: [Int] -> Int sum = foldr (+) 0 The composition of mapcube and sum gives a non-error-checking version of mmapcube which be fused via the foldr/build rule, also given in Figure 1, as follows: sum (mapcube xs) = foldr (+) 0 (build (\c n -> foldr (c . cube) n xs)) = (\c n -> foldr (c . cube) n xs) (+) 0 = foldr ((+) . cube) 0 xs Note that the intermediate list produced by mapcube and immediately consumed by sum in sum (mapcube xs) is not constructed by the fused program. In the monadic setting we wish to eliminate not just the intermediate list of cubes, but rather an entire intermediate structure of type Maybe [Int]. In general, in the monadic setting we seek to eliminate not just intermediate data structures, but intermediate data structures within monadic contexts. In the case of msumOfCubes we can write the monadic consumer msum in terms of the standard fold combinator for lists. Indeed we have msum = foldr (\x p -> do {v (f a -> a) -> Mu f -> a fold h (In k) = h (fmap (fold h) k) build :: Functor f => (forall a. (f a -> a) -> c -> a) -> c -> Mu f build g = g In fold k . build g = g k FIGURE 2. The fold and build combinators and fold/build rule. binds) of functions written in terms of monadic fold and build, and show how it solves the msumOfCubes problem outlined above. Finally, we prove the correctness of our monadic short cut fusion rule. Our monadic combinators and short cut fusion rule are given in Figure 3 and explained in Section 2.2. As we shall see later, their conceptual basis lies in the observation that, in a monadic setting, it is fruitful to consider not just standard algebras — i.e., pure functions f a -> a where f is the functor underlying the datatype of the inductive structure to be eliminated “in context” — but rather monadic algebras, i.e., functions f a -> m a where m is the monad in question. Just as the monadic fold combinator consumes monadic, rather than standard, algebras, so the monadic build combinator introduced herein quantifies over monadic, rather than standard, algebras. Our monadic short cut fusion rule thus eliminates not just intermediate data structures, like [t], but also intermediate structures situated in monadic contexts, like Maybe [t]. The remainder of this paper is structured as follows. In Section 2 we discuss background and related work; in particular we consider the relative merits of structuring code using standard fold and monadic fold. In Section 3 we apply our monadic fusion rule to a larger application, namely an interpreter for nondeterministic expressions. In Section 4 we prove our main result, the correctness of our monadic fusion rule. In Section 5 we consider its coalgebraic dual. Finally, in Section 6 we set out some directions for future work and conclude. 2 BACKGROUND AND RELATED WORK 2.1 Short Cut Fusion for Inductive Types Inductive datatypes are fixed points of functors. Functors can be implemented in Haskell as type constructors supporting fmap functions as follows: class Functor f where fmap :: (a -> b) -> f a -> f b The function fmap is expected to satisfy the two semantic functor laws stating that fmap preserves identities and composition. It is well-known that analogues of foldr exist for every inductive datatype. As shown in [3, 4], every inductive type also has an associated generalized build combinator and fold/build rule; these mfold :: (Functor f, Monad m, Dist f m) => (f a -> m a) -> Mu f -> m a mfold h = fold (\xs -> delta xs >>= h) mbuild :: (Functor f, Monad m) => (forall a. (f a -> m a) -> c -> m a) -> c -> m (Mu f) mbuild g = g (return . In) mbuild g c >>= mfold h = g h c FIGURE 3. The mfold and mbuild combinators and mfold/mbuild rule. can be implemented generically in Haskell as in Figure 2. There, Mu f represents the least fixed point of the functor f, and In represents the structure map for f, i.e., the “bundled” constructors for the datatype Mu f. The “extra” type c in the type of build is motivated in citegjuv05,guv03 and to lesser extent in Section 4 below. The fold/build rule for inductive types can be used to eliminate data structures of type Mu f from computations. The foldr and build combinators for lists can be recovered by taking f to be the functor whose fixed point is [b]; the foldr/build rule can be recovered by taking, in addition, c to be the unit type. 2.2 Short Cut Fusion in the Presence of Monads Monads model a variety of computational effects. They are implemented in Haskell as type constructors supporting >>= and return operations as follows: class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b These operations are expected to satisfy the semantic monad laws [9]. The monadic fold combinator mfold given in Figure 3 is well-known [1, 10, 11]. It is defined in terms of the standard fold and a distributivity law delta :: f (m a) -> m (f a) which describes how the results of monadic computations embodied by m on components of a data structure described by a functor f are propagated to the overall data structure; distributivity laws can be implemented in Haskell using the class Dist f m of types, each of which supports a distributivity law for f and m. But, until now, a monadic build which complements the monadic fold in the same way that the standard build complements the standard fold has not been given. Thus, although monadic fusion has been studied by other researchers [8, 10, 11, 12], all techniques developed thus far involve the standard fold rather than its monadic counterpart. In particular, a monadic short cut fusion rule – i.e., a short cut rule for programs expressed in terms of monadic fold and monadic build — has until now not been studied. To define a monadic build combinator we first observe that the functional argument to such a build, and thus the monadic build combinator itself, must have a monadic return type. Moreover, just as we expect the functions the monadic fold mfoldl :: Monad m => (Int -> a -> m a) -> m a -> [Int] -> m a mfoldl c n = foldr (\ i y -> do {v a -> m a) -> m a -> c -> m a) -> c -> m [Int] mbuildl g = g (\ x y -> return (x:y)) (return []) mbuildl g k >>= mfoldl c n = g c n k FIGURE 4. The mfoldl and mbuildl combinators and mfoldl/mbuildl rule. combinator uses to consume a data structure to have monadic return types, we also expect the monadic build combinator to quantify over all uses of functions with monadic return types to consume such structures. This leads us to define the monadic build combinator mbuild given in Figure 3. Then, to optimize modular programs constructed from these combinators we can also introduce the monadic short cut fusion rule for mfold and mbuild given there. Unlike the monadic fusion rule of [11], which eliminates the data structure but leaves the monadic context in which it is situated intact, the rule in Figure 3 eliminates both the entire intermediate data structure and its entire monadic context. The correctness of this rule is the main result of this paper. We prove it in Section 4 below. To demonstrate the monadic combinators and fusion rule, we use them to solve the msumOfCubes problem from the introduction. We can specialize the combinators and rule in Figure 3 to f x = N | C Int x, m = Maybe, and delta N = Just N delta (C i y) = do {v outOfRange (x + y)) (return 0) mmapcube = mbuildl g where g :: (Int -> a -> Maybe a) -> Maybe a -> [Int] -> Maybe a g c n [] = n g c n (v:vs) = do {k >= msum = mbuildl g xs >>= mfoldl (\x y -> outOfRange (x + y)) (return 0) = g (\x y -> outOfRange (x + y)) (return 0) xs
منابع مشابه
Short Cut Fusion of Recursive Programs with Computational Effects
Fusion is the process of improving the efficiency of modularly constructed programs by transforming them into monolithic equivalents. This paper defines a generalization of the standard build combinator which expresses uniform production of functorial contexts containing data of inductive types. It also proves correct a fusion rule which generalizes the fold/ build and fold/buildp rules from th...
متن کاملMonadic Corecursion |deenition, Fusion Laws, and Applications|
This paper investigates corecursive deenitions which are at the same time monadic. This corresponds to functions that generate a data structure following a corecursive process, while producing a computational eeect modeled by a monad. We introduce a functional, called monadic anamorphism, that captures deenitions of this kind. We also explore another class of monadic recursive functions, corres...
متن کاملPeano Arithmetic May Not Be Interpretable in the Monadic Theory of Order
Gurevich and Shelah have shown that Peano Arithmetic cannot be interpreted in the monadic second-order theory of short chains (hence, in the monadic secondorder theory of the real line). We will show here that it is consistent that there is no interpretation even in the monadic second-order theory of all chains.
متن کاملPromotional Transformation on Monadic Programs
Monads, proposed by Moggi [16] of their use in structuring denotational descriptions and then popularized by Wadler[21], are becoming an increasingly important tool for structural functional programming[8, 10, 11]. The reason is that monads provide a uniform framework for describing a wide range of programming language features including, for example, state, I/O, continuations, exceptions, pars...
متن کاملA New One-Pass Transformation into Monadic Normal Form
We present a translation from the call-by-value λ-calculus to monadic normal forms that includes short-cut boolean evaluation. The translation is higher-order, operates in one pass, duplicates no code, generates no chains of thunks, and is properly tail recursive. It makes a crucial use of symbolic computation at translation time.
متن کاملذخیره در منابع من
با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید
عنوان ژورنال:
دوره شماره
صفحات -
تاریخ انتشار 2009